home *** CD-ROM | disk | FTP | other *** search
-
- ┌──────────────────────────┐
- │ Programming the Keyboard │
- └──────────────────────────┘
-
- Written for the PC-GPE by Mark Feldman
- e-mail address : u914097@student.canberra.edu.au
- myndale@cairo.anu.edu.au
-
- ┌───────────────────────────────────────────┐
- │ THIS FILE MAY NOT BE DISTRIBUTED │
- │ SEPARATE TO THE ENTIRE PC-GPE COLLECTION. │
- └───────────────────────────────────────────┘
-
-
- ┌────────────┬───────────────────────────────────────────────────────────────
- │ Disclaimer │
- └────────────┘
-
- I assume no responsibility whatsoever for any effect that this file, the
- information contained therein or the use thereof has on you, your sanity,
- computer, spouse, children, pets or anything else related to you or your
- existance. No warranty is provided nor implied with this information.
-
- ┌──────────┬─────────────────────────────────────────────────────────────────
- │ Overview │
- └──────────┘
-
- The operation of the keyboard is really quite simple. Every time a key
- is pressed or released an interrupt 9 is generated, and reading the value
- from port 60h tells you what happened.
-
- ┌────────────────────────────┬───────────────────────────────────────────────
- │ Decoding the Keyboard Byte │
- └────────────────────────────┘
-
- So let's say you've installed an interrupt handler to handle all keyboard
- events and when an interrupt is generated your handler reads the byte from
- port 60h. What now?
-
- Well..each key on the keyboard has an associated scan code which is contained
- in the lower 7 bits of the byte. The most significant bit (ie bit 7) tells
- you what was actually done, 0 = key was just pressed, 1 = key was just
- released. If someone had just pressed the ESC key for instance, the port will
- show a value of 1 (1 is the ESC key's scan code). If they hold their finger
- on the button the keyboard will keep generating interrupt 9's and each
- time the port will still show a value of 1. When the person releases the key
- a final interrupt will be generated and the port will return 129 (1 + 128,
- since the high bit will be set indicating the person has released the key).
-
- Well...it's almost this simple. Some keys are "extended" keys. When an
- extended key is pressed an interrupt is generated and the keyboard port
- will return a value of 224 (E0h). This means that an extended key was pressed
- and it's *extended* scan code will be available during the *next* interrupt.
- Note that the left control key has a scan code of 29, while the *right*
- control key has an *extended* scan code of 29. The same applies to the alt
- keys and the arrow keys (keypad arrows vs the other ones).
-
- It would be nice if all keys were created equal and we could just throw away
- the 224 extended bytes and handle all the other bytes normally. Unfortunately
- there are two buttons which on my machine at least (and others I have tested)
- do some really weird stuff:
-
- PrtScn
- ──────
- Pressing this button will send *2* extended characters to the handler, 42
- and 55, so the actual byte sequence will be 224, 42, 224, 55. (Also note
- that the left shift key has a regular scan code of 42, so there goes our
- idea of just throwing 224's away). Only the extended 55's are sent during
- auto-repeat. When the key is released, the two are sent again with the high
- bits set (224, 170, 224, and 183). If any of the shift or control keys are
- being held down when the PrtScn button is pressed then only the (224, 55) is
- sent when the key is pressed and only the (224, 183) is sent when it's
- released. If the alt key is being held down (System Request) then the key
- behaves like an ordinary key with scan code 84. The practical upshot of all
- this is that the handlers you write to handle normal keys and extended keys
- will work fine with all the different PrtScn combinations (although a program
- would have to check normal key 84 *AND* extended key 55 in order to determine
- if the key is currently being pressed).
-
- Pause/Break
- ───────────
- Welcome to hell. If you press this key while either of the the control keys
- are being held down, it will behave like extended key 70, at all other times
- it will send the following bytes: (225, 29, 69, 225, 157, 197). Holding the
- key down does not result in autorepeat. Taking your finger off the key does
- not send any extra bytes, they appear to be sent after the "key down" bytes
- when you first press the key. Notice that 225 isn't 224, so our normal
- extended character handler will not take care of this. My personal theory is
- that while a scan code of 224 (E0h) means there is 1 more character
- following, a scan code of 225 (E1h) means there are *2* more following. I've
- seen a number of keyboard handler libraries and they all seem to overlook
- this key. So why not be the first kid on your block to have a keyboard
- handler which properly supports the Pause/Break key? CHECK IT OUT!!
-
- ┌───────────────────┬────────────────────────────────────────────────────────
- │ Writing a Handler │
- └───────────────────┘
-
- Writing a keyboard handler is fairly straightforward. This section will
- show how to do it in Pascal (you C and asm programmers would probably already
- know this stuff anyway).
-
- First we'll declare a few things we'll need:
-
- const KEYBOARDINTR = 9;
- KEYBOARDPORT = $60;
-
- var BIOSKeyboardHandler : procedure;
- CallBIOSHandler : boolean;
-
- The CallBIOSHandler variable will be initialised by the calling program. If
- we also want the BIOS handler to process all keystrokes then this variable
- must be set to true.
-
- Next we need to store the value of the current handler and set up own our
- own one. We'll use a procedure called KeyboardHandler to handle the actual
- interrupt.
-
- CallBIOSHandler := false; { ...or set it to true if you want. }
- GetIntVec(KEYBOARDINTR, @BIOSKeyboardHandler);
- SetIntVec(KEYBOARDINTR, Addr(KeyboardHandler));
-
- Ok, so everything is now set up and our handler will now be able to process
- all keyboard events. The actual interrupt handler could look like this:
-
- {$F+}
- procedure KeyboardHandler(Flags, CS, IP, AX, BX, CX, DX,
- SI, DI, DS, ES, BP: Word);
- interrupt;
- var key : byte;
- begin
-
- key := Port[KEYBOARDPORT];
-
- { PROCESS THE KEYSTROKE HERE }
-
- if CallBIOSHandler then
-
- { Call the BIOS keyboard handler if the calling program wants us to }
- begin
- asm pushf end;
- BIOSKeyboardHandler;
- end
-
- { Otherwise just acknowledge the interrupt }
- else Port[$20] := $20;
- end;
- {$F-}
-
-
- When the program is finished we can set the old keyboard handler again:
-
- SetIntVec(KEYBOARDINTR, @BIOSKeyboardHandler);
-
- ┌───────────────────┬────────────────────────────────────────────────────────
- │ A Word of Warning │
- └───────────────────┘
-
- When I was writing a simple handler to test the info in this file I did
- something REALLY stoopid which I would like to share with the world. I
- thought that my program was stuffing the keyboard up because when I exited
- the program my editor (Borland Pascal 7.0) would act as though the control
- button was being held down (I'm sure some of you have already started
- laughing by now). I had to press it after each time I ran the program
- just to sort it out. After spending a few hours looking all over the place
- for info on what could possibly be wrong I realised what I was doing. I was
- pressing CTRL-F9 to compile the program which would also immediately make it
- run and I was releasing the control key when my program was running, ie the
- regular BIOS handler was not getting the control key's "key up" command and
- still thought it was being held down when my program returned control to
- it. Moron.....
-
- ┌────────────┬───────────────────────────────────────────────────────────────
- │ Scan Codes │
- └────────────┘
-
- The following is a list of all the regular key scan codes in numerical
- order:
-
- Scan Scan
- Code Key Code Key
- ────────────────────────── ──────────────────────────
- 1 ESC 44 Z
- 2 1 45 X
- 3 2 46 C
- 4 3 47 V
- 5 4 48 B
- 6 5 49 N
- 7 6 50 M
- 8 7 51 , <
- 9 8 52 . >
- 10 9 53 / ?
- 11 0 54 RIGHT SHIFT
- 12 - _ 55 * (KEYPAD)
- 13 = + 56 LEFT ALT
- 14 BACKSPACE 57 SPACEBAR
- 15 TAB 58 CAPSLOCK
- 16 Q 59 F1
- 17 W 60 F2
- 18 E 61 F3
- 19 R 62 F4
- 20 T 63 F5
- 21 Y 64 F6
- 22 U 65 F7
- 23 I 66 F8
- 24 O 67 F9
- 25 P 68 F10
- 26 [ { 69 NUMLOCK (KEYPAD)
- 27 ] } 70 SCROLL LOCK
- 28 ENTER (RETURN) 71 7 HOME (KEYPAD)
- 29 LEFT CONTROL 72 8 UP (KEYPAD)
- 30 A 73 9 PGUP (KEYPAD)
- 31 S 74 - (KEYPAD)
- 32 D 75 4 LEFT (KEYPAD)
- 33 F 76 5 (KEYPAD)
- 34 G 77 6 RIGHT (KEYPAD)
- 35 H 78 + (KEYPAD)
- 36 J 79 1 END (KEYPAD)
- 37 K 80 2 DOWN (KEYPAD)
- 38 L 81 3 PGDN (KEYPAD)
- 39 ; : 82 0 INSERT (KEYPAD)
- 40 ' " 83 . DEL (KEYPAD)
- 41 ` ~ 87 F11
- 42 LEFT SHIFT 88 F12
-
-
- The following is a list of all the extended key scan codes in numerical
- order:
-
- Scan Scan
- Code Key Code Key
- ─────────────────────────────── ───────────────────────────────
- 28 ENTER (KEYPAD) 75 LEFT (NOT KEYPAD)
- 29 RIGHT CONTROL 77 RIGHT (NOT KEYPAD)
- 42 PRINT SCREEN (SEE TEXT) 79 END (NOT KEYPAD)
- 53 / (KEYPAD) 80 DOWN (NOT KEYPAD)
- 55 PRINT SCREEN (SEE TEXT) 81 PAGE DOWN (NOT KEYPAD)
- 56 RIGHT ALT 82 INSERT (NOT KEYPAD)
- 71 HOME (NOT KEYPAD) 83 DELETE (NOT KEYPAD)
- 72 UP (NOT KEYPAD) 111 MACRO
- 73 PAGE UP (NOT KEYPAD)
-
-